package top.malaoshi.webmvc;


import org.springframework.util.ClassUtils;
import top.malaoshi.easy.logging.Log;
import top.malaoshi.easy.logging.LogFactory;
import top.malaoshi.util.StringUtil;
import top.malaoshi.web.utils.PathUtils;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.FileAlreadyExistsException;
import java.util.Map;
import java.util.Properties;

/**
 * 读取 classpath、WEB-INF 目录下 application.yaml、application.properties 配置文件 <br>
 * 先加载 classpath 目录下文件，依次加载 application.yml,application.yaml,application.properties <br>
 * 然后加载 WEB-INF 目录下文件，依次加载 application.yml,application.yaml,application.properties<br>
 *
 * <b>只能读取一个配置文件</b>
 */
public class ApplicationConfigFileReader {

    static final Log LOG = LogFactory.getLog(ApplicationConfigFileReader.class);
    private static final String[] DEFAULT_NAMES = {"application.yml","application.yaml","application.properties"};

    private URL url ;
    /**
     * 必须创建对象
     * 如果没有配置文件时，又使用了@Value注解，从该成员变量取值时，会报 NullPointerException 异常
     */
    private static Properties properties = new Properties();

    public void handler(){
        try {
            sannerClasspath();
            sannerWebinf();
        } catch (FileAlreadyExistsException e) {
            LOG.error("",e);
        }
        if(url==null){

            StringBuilder msg = StringUtil.append("没有找到 ",DEFAULT_NAMES,"、")
                    .append(" 配置文件！");
            LOG.trace(msg.toString());

            return;
        }
        try {
            readProperties();
        } catch (IOException e) {
            LOG.error("",e);
        }
        try {
            readYmal();
        } catch (IOException e) {
            LOG.error("",e);
        }

    }
    /**
     * 扫描 classpath 或 jar中的配置文件
     */
    private void sannerClasspath() throws FileAlreadyExistsException {

        for(String name : DEFAULT_NAMES) {
            URL urlTemp = ClassUtils.getDefaultClassLoader().getResource(name);

            if(urlTemp!=null){
                if(url!=null ) {
                    throw new FileAlreadyExistsException("已经加载 " + url.getFile() + " ，不能再加载 " + urlTemp.getFile());
                }
                url = urlTemp;
            }
        }
    }


    /**
     * 扫描web-inf目录下的文件
     * @throws FileAlreadyExistsException
     */
    private void sannerWebinf() throws FileAlreadyExistsException {

        for(String name : DEFAULT_NAMES) {
            // 加载 WEB-INF 下的配置文件
            File fileWebinf = PathUtils.getWebInfPath(name);
            if(fileWebinf.exists()){
                if(url!=null){
                    throw new FileAlreadyExistsException("已经加载 "+url.getFile()+" ，不能再加载 "+fileWebinf);
                }
                try {
                    url = new URL("file:/"+fileWebinf.getAbsolutePath());
                } catch (MalformedURLException e) {
                    throw new RuntimeException(e);
                }
            }

        }
    }
    // 读取properties配置文件
    private void readProperties() throws IOException {

        if(url.getFile().endsWith(".properties")){
            properties = new Properties();
            try(InputStream fis = url.openStream()) {

                try(InputStreamReader isr = new InputStreamReader(fis,"UTF-8")){
                    properties.load(isr);
                }
            }
        }
    }
    // 读取yaml配置文件
    private void readYmal() throws IOException {

        if(url.getFile().endsWith(".yaml") || url.getFile().endsWith(".yml")){
            YmalReader reader = new YmalReader();
            try(InputStream is = url.openStream()) {
                if(is.available()==0){// 文件内容为空时不读取
                    return;
                }
                reader.load(is);
                Map map = reader.getMap();
                properties = new Properties();
                map.forEach((key,value)->{
                    properties.put(key,value);
                });
            }
        }
    }

    public static Properties getProperties(){
        return properties;
    }

    public static Object getValue(String key){
        return properties.get(key);
    }
}
